package userInterface;

import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Scanner;
import regression.Regression;
import regression.RegressionUtils;
import regression.User;

public class UserInterface {

    public static final String CHOICE_ONE = "1";
    public static final String CHOICE_TWO = "2";
    public static final String CHOICE_THREE = "3";
    public static final String CHOICE_FOUR = "4";
    public static final String CHOICE_FIVE = "5";
    public static final String CHOICE_ZERO = "0";
    public static final String CHOICE_Y = "y";
    public static final String CHOICE_N = "n";
    public static final String PORT_PATTERN = "\\d+";
    public static final String IPADDRESS_PATTERN = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
            + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
            + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
            + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";

    public static void main(String[] args) {
        UserInterface ui = new UserInterface();
        Scanner sc = new Scanner(System.in);
        boolean exit = false;
        while (!exit) {
            ui.printInstruction();
            String cmd = sc.nextLine();
            if (cmd.equals(CHOICE_ONE)) {
                ui.doCreateRegression();
                exit = true;
            } else if (cmd.equals(CHOICE_TWO)) {
                ui.doJoinRegression();
                exit = true;
            } else if (cmd.equals(CHOICE_ZERO)) {
                exit = true;
            }
        }
        sc.close();
    }

    public void printInstruction() {
        System.out.println(UserInterfaceOutput.HEADER);
        System.out.print(UserInterfaceOutput.INSTRUCTION);
    }

    public void doCreateRegression() {
        Regression regression = new Regression();
        boolean exit = false;
        Scanner sc = new Scanner(System.in);
        doAddCreator(regression, sc);
        while (!exit) {
            System.out.print(UserInterfaceOutput.CREATE_REGRESSION_INSTRUCTION);
            String cmd = sc.nextLine();
            if (cmd.equals(CHOICE_ONE)) {
                doAddUser(regression, sc);
            }
            if (cmd.equals(CHOICE_TWO)) {
                doRemoveUser(regression, sc);
            }
            if (cmd.equals(CHOICE_THREE)) {
                doListUsers(regression);
            }
            if (cmd.equals(CHOICE_FOUR)) {
                doCreatorStartRegression(regression, sc);
            }
            if (cmd.equals(CHOICE_ZERO)) {
                exit = true;
            }
        }
        sc.close();
    }

    public void doAddCreator(Regression regression, Scanner sc) {
        while (true) {
            System.out.print(UserInterfaceOutput.ENTER_YOUR_PORT);
            String cmd = sc.nextLine();
            if (cmd.matches(PORT_PATTERN)) {
                int port = Integer.valueOf(cmd);
                User creator = new User();
                creator.setPort(port);
                String ip = "";
                try {
                    ip = Inet4Address.getLocalHost().getHostAddress();
                    creator.setIp(ip);
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                creator.setConnected(true);
                regression.setCreator(creator);
                regression.setCurrentUser(creator);
                while (true) {
                    System.out.print(UserInterfaceOutput.ARE_YOU_DATA_SOURCE);
                    cmd = sc.nextLine();
                    if (cmd.equals(CHOICE_Y)) {
                        regression.addUser(creator);
                        break;
                    } else if (cmd.equals(CHOICE_N)) {
                        break;
                    }
                }
                System.out.println("Regression creator successfully added.");
                System.out.println("IPv4 address: " + ip);
                System.out.println("Port number: " + port);
                break;
            } else {
                System.out.println(UserInterfaceOutput.INVALID_PORT);
            }
        }
    }

    public void doAddUser(Regression regression, Scanner scanner) {
        User user = new User();
        System.out.println(UserInterfaceOutput.ADD_USER);
        while (true) {
            System.out.print(UserInterfaceOutput.USER_IP);
            String cmd = scanner.nextLine();
            if (cmd.matches(IPADDRESS_PATTERN)) {
                user.setIp(cmd);
                break;
            } else {
                System.out.println(UserInterfaceOutput.INVALID_IP);
            }
        }
        while (true) {
            System.out.print(UserInterfaceOutput.USER_PORT_NUMBER);
            String cmd = scanner.nextLine();
            if (cmd.matches(PORT_PATTERN)) {
                int port = Integer.valueOf(cmd);
                user.setPort(port);
                break;
            } else {
                System.out.println(UserInterfaceOutput.INVALID_PORT);
            }
        }
        regression.addUser(user);
        System.out.println(UserInterfaceOutput.USER_ADDED);
    }

    public void doListUsers(Regression regression) {
        List<User> users = regression.getDataSourceUsers();
        if (users.isEmpty()) {
            System.out.println(UserInterfaceOutput.NO_USER);
            return;
        }
        System.out.println(UserInterfaceOutput.USER_LIST);
        int i = 1;
        for (User u : users) {
            System.out.println(i + ". " + u.getIp() + ":" + u.getPort());
            i++;
        }
    }

    public void doRemoveUser(Regression regression, Scanner sc) {
        doListUsers(regression);
        List<User> list = regression.getDataSourceUsers();
        if (list.isEmpty()) {
            return;
        }
        System.out.print(UserInterfaceOutput.REMOVE_USER);
        String cmd = sc.nextLine();
        if (cmd.matches(PORT_PATTERN)) {
            int choice = Integer.valueOf(cmd);
            if (1 <= choice && choice <= list.size()) {
                choice--;
                list.remove(choice);
                System.out.println(UserInterfaceOutput.USER_REMOVED);
                return;
            }
        }
        System.out.println(UserInterfaceOutput.INVALID_CHOICE);
    }

    public void doCreatorStartRegression(Regression regression, Scanner sc) {
//		regression.startMessageListener();
        System.out.println(UserInterfaceOutput.LISTENER_STATRED);
        System.out.println(UserInterfaceOutput.WAITE);
        while (!RegressionUtils.checkAllUserConnected(regression)) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public void doJoinRegression() {
        Regression regression = new Regression();
        User creator = new User();
        Scanner sc = new Scanner(System.in);
        System.out.println(UserInterfaceOutput.ENTER_CREATOR_INFORMATION);
        while (true) {
            System.out.print(UserInterfaceOutput.CREATOR_IP);
            String cmd = sc.nextLine();
            if (cmd.matches(IPADDRESS_PATTERN)) {
                creator.setIp(cmd);
                break;
            } else {
                System.out.println(UserInterfaceOutput.INVALID_IP);
            }
        }
        while (true) {
            System.out.print(UserInterfaceOutput.CREATOR_PORT_NUMBER);
            String cmd = sc.nextLine();
            if (cmd.matches(PORT_PATTERN)) {
                int port = Integer.valueOf(cmd);
                creator.setPort(port);
                break;
            } else {
                System.out.println(UserInterfaceOutput.INVALID_PORT);
            }
        }
        regression.setCreator(creator);
        User user = new User();
        String ip = "";
        try {
            ip = Inet4Address.getLocalHost().getHostAddress();
            user.setIp(ip);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        while (true) {
            System.out.print(UserInterfaceOutput.ENTER_YOUR_PORT);
            String cmd = sc.nextLine();
            if (cmd.matches(PORT_PATTERN)) {
                int port = Integer.valueOf(cmd);
                user.setPort(port);
                break;
            } else {
                System.out.println(UserInterfaceOutput.INVALID_PORT);
            }
        }
        user.setConnected(true);
        regression.setCurrentUser(user);
        regression.addUser(user);
        doJoinerStartRegression(regression, sc);
        sc.close();
    }

    public void doJoinerStartRegression(Regression regression, Scanner sc) {
//		regression.pingUser(regression.getCreator());
        System.out.println(UserInterfaceOutput.WAITE);
        while (!RegressionUtils.checkAllUserConnected(regression)) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
